package arbre.utils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;



public class Segment implements Serializable,Comparable<Segment>{

	private Point debut;
	private Point fin;
	private Zone haut;
	private Zone bas;

	private String id;
	private String type;

	public List<String> intersections = new ArrayList<String>();
	public List<String> polygones = new ArrayList<String>();

	public Segment(){
		
	}
	public Segment(Point debut, Point fin) {
		super();

		this.debut = debut;
		this.fin = fin;

	}

	public int superHashCode() {
		return super.hashCode();
	}

	public Segment trie() {
		assert !debut.equals(fin);
		if (debut.getY() > fin.getY() || (debut.getY()==fin.getY() && debut.getX()<=fin.getX()))
			return new Segment(debut,fin);
		else
			return new Segment(fin,debut);

	}

	public float norme(){
		float x2 = fin.getX()-debut.getX();
		float y2 = fin.getY()-debut.getY();
		x2 *= x2;
		y2 *= y2;
		return (float) Math.sqrt(x2+y2);
	}

	public Point intersectionHorizontale(float y) {
		if ((debut.getY() - y) * (fin.getY() - y) > 0)
			return null;
		else if (debut.getY() == fin.getY())
			return null;
		else {
			float x = ((fin.getY() - y) * debut.getX() + (y - debut.getY()))
					/ (fin.getY() - debut.getY());
			return new Point(x, y);
		}
	}

	public float produitVectoriel(Segment s) {
		return (fin.getX() - debut.getX()) * (s.fin.getY() - s.debut.getY()) - 
				(fin.getY() - debut.getY()) * (s.fin.getX() - s.debut.getX());
	}

	public float produitScalaire(Segment s) {
		return (fin.getX() - debut.getX()) * (s.fin.getX() - s.debut.getX()) + 
				(fin.getY() - debut.getY()) * (s.fin.getY() - s.debut.getY());
	}

	public boolean contains(Point p) {
		Segment s = new Segment(debut, p);
		float prodVect = produitVectoriel(s);
		System.out.println("prodVect :"+prodVect);
		
		float prodScalaire_s =  produitScalaire(s);
		System.out.println("prodScalaire_s :"+prodScalaire_s);
		
		float prodScalaire_me = produitScalaire(this);
		System.out.println("prodScalaire_me :"+produitScalaire(this));
		
		return ( prodVect == 0 
				&& prodScalaire_s >= 0 
				&& prodScalaire_s <= prodScalaire_me);
	}

	public Point intersection(Segment s) {
		if (s.produitVectoriel(this) == 0)
			return null;

		float a = (s.produitVectoriel(new Segment(debut, s.debut)))
				/ s.produitVectoriel(this);

		if (a < 0 || a > 1)
			return null;
		else
			return new Point(debut.getX() + a * (fin.getX() - debut.getX()), debut.getY() + a
					* (fin.getY() - debut.getY()));
	}

	public Point projectionHorizontale(Point p) {
		Point pointHorizon = new Point(p.getX()+1+p.getX()/2,p.getY());
		Segment demiHorizon = new Segment(p,pointHorizon);
		if(produitVectoriel(demiHorizon) == 0)
			return null;
		else {
			float lambda = produitVectoriel(new Segment(debut, p)) / produitVectoriel(demiHorizon);
			return p.translation(demiHorizon.homethetie(lambda));
		}
	}

	public Segment homethetie(float lambda) {
		return new Segment(debut.homethetie(lambda),fin.homethetie(lambda));
	}

	/**
	 * @author trt
	 * @param x abscisse a rechercher
	 * @return retourne le point d'abscisse x sur le segment
	 * ou null si le segmet n'est pas defini dans l'abscisse 
	 * 
	 */
	//TODO voir si ce n'est pas plus pratique d'envoyer un float pour le y directement
	public Point getCoord(float x)
	{
		if((x >= debut.getX() && x <= fin.getX()) || 
				(x <= fin.getX() && x <= debut.getX() ) )
		{
			// y = (xb -xa)/(yb-ya) * x
			float coeff = (fin.getX() - debut.getX())/(fin.getY() - debut.getX());

			return new Point(x,coeff * x);
		}
		else
		{
			//l'abscisse x n'a pas d'iuntersection avec le segment
			return null;
		}
	}
	
	public static double distance(Point fin,Point p2) {
		double dx=fin.getX()-p2.getX();
		double dy=fin.getY()-p2.getY();
		return Math.sqrt(dx*dx+dy*dy);
	}

	 
	public String toString() {
		StringBuffer st = new StringBuffer("\t<chemin ");

		st.append("id=\"").append(this.id).append("\" ");
		st.append("type=\"").append(this.type).append("\" ");
		st.append(">\n\n");

		// On affiche les points du segments
		st.append("\t\t"+this.debut.toString()+"\n");
		st.append("\t\t"+this.fin.toString()+"\n");

		// On affiche les batiments
		for(String b : polygones)
			st.append("\n\t\t<polygone id=\""+ b +"\"/>");

		st.append("\n");

		// On affiche les chemins qui parte du segments
		for(String s : intersections)
			st.append("\n\t\t<segment id=\""+ s +"\"/>");





		st.append("\n");

		st.append("\n\t</chemin>");
		return st.toString();
	}

	public String toDot(){
		return "s"+id;
	}

	 
	public Point getDebut() {
		return this.debut;
	}

	 
	public void setDebut(Point p) {
		this.debut = p;
	}

	 
	public Point getFin() {
		return this.fin;
	}

	 
	public void setFin(Point p) {
		this.fin = p ;
	}

	 
	public Zone getHaut() {
		return haut;
	}

	 
	public void setHaut(Zone haut) {
		this.haut = haut;
	}

	 
	public Zone getBas() {
		return bas;
	}

	 
	public void setBas(Zone bas) {
		this.bas = bas;
	}

	 
	public int compareTo(Segment o) {
		// comparer les segments pour les renvoyer dans l'ordre de leur ordonn��e
		// 

		if (debut.getY() < o.getDebut().getY())
			return -1;
		else if (debut.getY() > o.getDebut().getY())
			return 1;
		else if (debut.getX() < o.getDebut().getX())
			return -1;
		else if (debut.getX() > o.getDebut().getX())
			return 1;
		else 
			return 0;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public float produitVectoriel(Point a, Point b, Point c) {
		return ((b.getX()-a.getX())*(c.getY()-a.getY()))-((b.getY()-a.getY())*(c.getX()-a.getX()));

	}

	public boolean dessous(Point p) {
		if(p.getY() > debut.getY() && p.getY()>fin.getY()){
			return false;
		}
		else if (p.getY() < debut.getY() && p.getY()<fin.getY()){
			System.out.println("dessous");

			return true;
		}
		else{
			if(debut.compareTo(fin) <= 0){
				//debut est en bas a gauche de fin
				//donc debut->fin,debut->p doit touner dnas le sens horaire, pVect <0
				if(produitVectoriel(debut, fin, p) <0){
					System.out.println("dessous");
					return true; //tournant dans le sens horaire
				}
				else{
					return false;
				}
			}
			else{
				//debut.compareTo(fin) >0
				//debut en haut a droite de fin
				//debut->fin, debut->p doit tourner à gauche(anti-horaire)
				if(produitVectoriel(debut, fin, p) >0){
					System.out.println("dessous");

					return true; //tournant dans le sens anti-horaire
				}
				else{
					return false;
				}
			}
		}
	}

	public boolean dessus(Point p) {
		if(p.getY() > debut.getY() && p.getY()>fin.getY()){
			System.out.println("dessus");

			return true;
		}
		else if (p.getY() < debut.getY() && p.getY()<fin.getY()){
			return false;
		}
		else{
			if(debut.compareTo(fin) <= 0){
				//				debut est a gauche ou en dessous de fin
				if(produitVectoriel(debut, fin, p) >0){
					//					donc debut->fin , debut->p doit tourner trigo(anti-horaire)
					System.out.println("dessus");
					return true;
				}
				else{
					return false; 	
				} 
			}
			else{
				//debut.compareto(fin) >0 , donc debut est en haut a droite de fin
				//donc debut->fin, debut->p doit tourner anti-horaire
				if(produitVectoriel(debut, fin, p) <0){
					System.out.println("dessus");

					return true;
				}
				else{
					return false; 

				}	
			}
		}
	}

	public void addIntersection(String id) {
		if(!intersections.contains(id))
			intersections.add(id);
	}

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public static void main(String args[]){
		Segment s = new Segment(new Point(0,0),new Point(0,2));
		Point p1 = new Point(0,1);
		Point p2 = new Point(1,0);
		Point p3 = new Point(0,3);

		System.out.println(s.contains(p1));
		System.out.println(s.contains(p2));
		System.out.println(s.contains(p3));
	}

	public List<String> getIntersections() {
		return intersections;
	}

	public void setIntersections(List<String> intersections) {
		this.intersections = intersections;
	}

	public List<String> getPolygones() {
		return polygones;
	}

	public void setPolygones(List<String> polygones) {
		this.polygones = polygones;
	}

}
